<?php
/**
 * Created by PhpStorm.
 * User: xmy2
 * Date: 18-8-9
 * Time: 上午10:36
 */

namespace vola;

use \vola\mirror\Config;

class Request
{

    private static $copy;
    /**
     * @var Config
     */
    private $cf;
    /**
     * @var Env
     */
    private $ev;

    public static function init()
    {
        if (empty(self::$copy)) {
            self::$copy = new static();
        }

        return self::$copy;
    }

    private $server = [],
        $post = [],
        $get = [],
        $controller = '',
        $module = '',
        $action = '',
        $suffix = '',
        $domain = '',
        $script = '';

    public function __construct()
    {
        $this->cf = Container::get('config');

        $this->ev = Container::get('env');
        parse_str(file_get_contents('php://input'), $this->post);
        if (empty($this->post)) {
            $this->post = $_POST;
        }

    }

    /**
     * 读取Server的东西
     * @param string $name 名称,不分大小写
     * @param string $value 要修改的值,不改则为''空
     * @param string $type 要转换的类型, 方便快速转换, 不用再写很多内容
     * @param string $filter 过滤函数 为null时 直接返回值
     * @return string|mixed|null|int|array|object
     */
    public function server($name, $value = '', $type = '*', $filter = '')
    {
        $name = strtoupper($name);
        if (empty($this->server)) {
            $this->server = $_SERVER;
        }

        if ($value != '') {
            if ($value === null) {
                unset($this->server[$name], $_SERVER[$name]);
            } else {
                $this->server[$name] = $value;
            }
            return null;
        }

        return $this->filter($this->server, $name, $type, $filter);
    }

    /**
     * 过滤函数
     * @param array $data 数据数组
     * @param string $name key名
     * @param string $type 转换的类型 默认* 直接返回值
     * @param string $filter 过滤函数, $type不为*的时候
     * @return mixed
     */
    private function filter($data, $name, $type = '*', $filter = '')
    {
        if (!isset($data[$name])) {
            return '';
        }
        $data = $this->filterType($data[$name], $type);
        if (empty($filter)) {
            return $data;
        }
        return call_user_func($filter, $data);
    }

    /**
     * 转换类型
     * @param $value
     * @param string $type
     * @return array|float|int|mixed|object|string
     */
    private function filterType($value, $type = 'string')
    {
        if ($type === "*") {
            return $value;
        }
        switch ($type) {
            case 'string':
                return strval($value);
            case 'int':
                return intval($value);
            case 'float':
                return floatval($value);
            case 'json':
                return json_encode($value);
            case 'object':
                return json_decode($value);
            case 'jsonArray':
                return json_decode($value, true);
            case 'price':
                return round($value, 2);
        }
    }

    public function path()
    {
        $config = $this->cf;
        if ($config->get('route.type') == 'pathinfo') {
            $path = !empty($this->server('path_info')) ? $this->server('path_info') : $this->server('query_string');

            if (!isset($this->server['PATH_INFO']) && empty($path)) {
                $path = $this->server('REQUEST_URI');
                $path = str_replace(basename($this->server('script_filename')), '', $path);
            }

        } else {
            $path = $this->get($config->get('route.query_name'));
        }

        $this->suffix();

        if (!empty($this->suffix)) {

            if (is_array($this->suffix)) {
                foreach ($this->suffix as $suffix) {
                    $path = str_replace($suffix, '', $path);
                }
            } else {

                $path = str_replace($this->suffix, '', $path);
            }
        }

        return $path;
    }


    /**
     * 获取$_GET
     * @param string $name
     * @param $value
     */
    public function get($name = '', $value = '', $type = 'string', $filter = '')
    {
        if (empty($this->get)) {
            $this->get = $_GET;
        }

        if ($name == '') {
            return $this->get;
        }

        if ($value != '') {
            if ($value == null) {
                unset($this->get[$name], $_GET[$name]);
            } else {
                $this->get[$name] = $value;
            }
        }

        return $this->filter($this->get, $name, $type, $filter);
    }

    /**
     * 获取$_POST
     * @param string $name
     * @param $value
     */
    public function post($name = '', $value = '', $type = '*', $filter = '')
    {
        if (empty($this->post)) {
            $this->post = $_POST;
        }

        if ($name == '') {
            return $this->post;
        }

        if ($value != '') {
            if ($value == null) {
                unset($this->post[$name], $_POST[$name]);
            } else {
                $this->post[$name] = $value;
            }
        }

        return $this->filter($this->post, $name, $type, $filter);
    }

    public function controller($name = '')
    {
        if ($name) {
            $this->controller = $name;
        }
        return $this->controller;
    }

    public function module($name = '')
    {
        if ($name) {
            $this->module = $name;
        }
        return $this->module;
    }

    public function action($name = '')
    {
        if ($name) {
            $this->action = $name;
        }
        return $this->action;
    }

    public function isPost()
    {
        return $this->server('REQUEST_METHOD') === 'POST';
    }

    public function isGet()
    {
        return $this->server('REQUEST_METHOD') === 'GET';
    }

    public function isAjax()
    {
        if (isset($_SERVER["HTTP_X_REQUESTED_WITH"]) && strtolower($_SERVER["HTTP_X_REQUESTED_WITH"]) == "xmlhttprequest") {
            return true;
        }

        return $this->cf->get('route.ajax') !== NULL && $this->get($this->cf->get('route.ajax')) !== '';
    }

    /**
     * 未修正
     * 获取指定路由名字
     * @param string $url
     * @param array $args
     */
    public function route($url = '', $args = [])
    {
        if (!empty($url)) {
            $c = substr_count($url, '/');
            if ($c < 2) {
                if ($c == 0) {
                    $url = $this->module() . '/' . $this->controller() . '/' . $url;
                } else {
                    $url = $this->module() . '/' . $url;
                }
            }
        } else {
            $url = $this->module() . '/' . $this->controller() . '/' . $this->action();
        }

        return str_replace('/', $this->cf->get('route.url_esp'), Container::get('route')->search($url, $args));
    }

    public function url($url = '', $args = [])
    {

        return $this->baseurl($this->route($url, $args));
    }


    /**
     * 获取Session
     *  判断 ?跟$name的值
     * 读取 $value 不写
     * 删除 $value = null
     * 删除全部 $name = null
     * @param $name
     * @param string $value
     */
    final public function session($name, $value = '')
    {
        $session = Container::get('session');
        if (empty($value) && $value !== null) {
            if ($name === null) {
                return $session->all();
            }
            if (strpos($name, '?') === false) {
                return $session->get($name);
            }
            return $session->has(trim($name, '?'));
        } else {
            if ($value === null) {
                $session->del($name);
            } else {
                $session->set($name, $value);
            }
        }
    }

    public function csrf_token($token = '')
    {
        if (!empty($token)) {
            return strcmp($token, $this->session('yf_csrf_token')) === 0;
        }

        $code = time();
        $rand = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z');
        shuffle($rand);
        $temp = array_rand($rand, 6);

        foreach ($temp as &$v) {
            $v = $rand[$v];
        }
        $code = md5($code . $temp);

        $this->session('yf_csrf_token', $code);
        return $code;
    }


    /**
     * 获取或设置url
     * @param string $url
     * @return string
     */
    public function baseurl($url = '')
    {
        if (!empty($url)) {
            return '/' . trim('/' . $this->script() . '/' . $url, '/') . $this->suffix();
        }
        return $this->server('REQUEST_URI');
    }

    public function script()
    {
        if ($this->ev->get('rewrite') === false) {
            if (empty($this->script)) {
                $script = $this->server('SCRIPT_NAME');
                $this->script = $script;
            }
            return $this->script;
        }
        return '';
    }

    /**
     * 设置伪静态后缀
     * @param string $suffix
     * @return bool
     */
    public function suffix($suffix = '')
    {

        if (empty($suffix)) {

            $this->suffix = $this->cf->get('route.url_html_suffix');

            if (strpos($this->suffix, '|')) {
                $this->suffix = explode('|', $this->suffix);
                foreach ($this->suffix as &$val) {
                    $val = '.' . $val;
                }
            } else {
                if (!is_array($this->suffix)) {
                    $this->suffix = '.' . $this->suffix;
                }
            }
        }

        if (is_array($this->suffix)) {
            $data = array_rand($this->suffix, 1);
            return $data[0];
        }

        if (!empty($suffix)) {
            $this->suffix = '.' . $suffix;
        }

        return $this->suffix;

    }

    public function is_rewirte()
    {
        if ($this->cf->get('use_rewirte')) {
            return true;
        }
        return false;
    }

    /**
     * 获取当前域名
     * @return string
     */
    public function domain()
    {
        if (empty($this->domain)) {
            $url = 'http://';
            if ($this->isSsl()) {
                $url = 'https://';
            }
            $url .= $this->host();
            $this->domain = $url . '/';
        }
        return $this->domain;
    }

    /**
     * 当前是否ssl
     * @access public
     * @return bool
     */
    public function isSsl()
    {
        $server = $_SERVER;
        if (isset($server['HTTPS']) && ('1' == $server['HTTPS'] || 'on' == strtolower($server['HTTPS']))) {
            return true;
        } elseif (isset($server['REQUEST_SCHEME']) && 'https' == $server['REQUEST_SCHEME']) {
            return true;
        } elseif (isset($server['SERVER_PORT']) && ('443' == $server['SERVER_PORT'])) {
            return true;
        } elseif (isset($server['HTTP_X_FORWARDED_PROTO']) && 'https' == $server['HTTP_X_FORWARDED_PROTO']) {
            return true;
        } elseif ($this->cf->get('https_agent_name') && isset($server[$this->cf->get('https_agent_name')])) {
            return true;
        } elseif ($this->cf->get('needssl')) {
            return true;
        }
        return false;
    }

    /**
     * 获取域名
     * @return bool
     */
    public function host()
    {
        if (isset($_SERVER['HTTP_X_REAL_HOST'])) {
            return $_SERVER['HTTP_X_REAL_HOST'];
        }
        return $this->server('HTTP_HOST');
    }

    /**
     * 获取客户端IP地址
     * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
     * @param boolean $adv 是否进行高级模式获取（有可能被伪装）
     * @return mixed
     */
    public function ip($type = 0, $adv = false)
    {
        $type = $type ? 1 : 0;
        static $ip = null;
        if (null !== $ip) {
            return $ip[$type];
        }

        if ($adv) {
            if (isset($this->server['HTTP_X_FORWARDED_FOR'])) {
                $arr = explode(',', $this->server['HTTP_X_FORWARDED_FOR']);
                $pos = array_search('unknown', $arr);
                if (false !== $pos) {
                    unset($arr[$pos]);
                }
                $ip = trim(current($arr));
            } elseif (isset($this->server['HTTP_CLIENT_IP'])) {
                $ip = $this->server['HTTP_CLIENT_IP'];
            } elseif (isset($_SERVER['REMOTE_ADDR'])) {
                $ip = $this->server['REMOTE_ADDR'];
            }
        } elseif (isset($this->server['REMOTE_ADDR'])) {
            $ip = $this->server['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u", ip2long($ip));
        $ip = $long ? [$ip, $long] : ['0.0.0.0', 0];
        return $ip[$type];
    }

    /**
     * 检测是否使用手机访问
     * @access public
     * @return bool
     */
    public function isMobile()
    {
        if (isset($_SERVER['HTTP_VIA']) && stristr($_SERVER['HTTP_VIA'], "wap")) {
            return true;
        } elseif (isset($_SERVER['HTTP_ACCEPT']) && strpos(strtoupper($_SERVER['HTTP_ACCEPT']), "VND.WAP.WML")) {
            return true;
        } elseif (isset($_SERVER['HTTP_X_WAP_PROFILE']) || isset($_SERVER['HTTP_PROFILE'])) {
            return true;
        } elseif (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/(blackberry|configuration\/cldc|hp |hp-|htc |htc_|htc-|iemobile|kindle|midp|mmp|motorola|mobile|nokia|opera mini|opera |Googlebot-Mobile|YahooSeeker\/M1A1-R2D2|android|iphone|ipod|mobi|palm|palmos|pocket|portalmmm|ppc;|smartphone|sonyericsson|sqh|spv|symbian|treo|up.browser|up.link|vodafone|windows ce|xda |xda_)/i', $_SERVER['HTTP_USER_AGENT'])) {
            return true;
        } else {
            return false;
        }
    }

}
